package summer.codegenerator.common.util;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import summer.codegenerator.Constant;

public class TokenUtil {
	
	/**
	 * 依据用户名生成令牌
	 * 
	 *
	 * 
	 * @param username
	 * @return
	 * @author: jiangz
	 * @date: Created on 2019年7月29日 上午10:26:42
	 */
	public static String generateToken(String username) {
		// 当前时间戳加密
		Long password = System.currentTimeMillis();
		byte encryptedBytes[] = aesEncrypt(username, password.toString());
		
		// 加密后的字节码转成便于传输的字符串
		Base64 base64 = new Base64();
		String encodedString = base64.encodeToString(encryptedBytes);
		
		setTokenPassword(encodedString, password);
		
		return encodedString;
	}
	
	/**
	 * 验证用户合法性
	 *
	 * 
	 * @param token
	 * @return
	 * @throws UnsupportedEncodingException
	 * @author: jiangz
	 * @date: Created on 2019年7月29日 上午10:26:57
	 */
	public static String legalUser(String token) throws UnsupportedEncodingException {
		Long current = System.currentTimeMillis();
		Long password = tokenPassword.get(token);
		String username =  null;
		if(password != null) {
			// 加密的字节码
			Base64 base64 = new Base64();
			byte encryptedBytes[] = base64.decode(token);
			
			// 解密
			username = new String(
					aesDecrypt(encryptedBytes, password.toString()),
					Constant.CHARACTERS_SET);
			
			if(StringUtils.isNotEmpty(username) && 
					current -password > Constant.USER_LOG_MAX_AGE * 60 * 1000) {
				username = null;
			}
		}
		return username;
	}
	
	private static Map<String, Long> tokenPassword = new HashMap<String, Long> ();
	
	private static synchronized void setTokenPassword(String token, Long password) {
		tokenPassword.put(token, password);
	}
	
	/**
	 * 
	 * 
	 * @param content	需要被加密的字符串
	 * @param password	加密需要的密码
	 * @return 密文
	 */
	private static byte[] aesEncrypt(String content, String password) {
		try {
			// AES secret key generator
			KeyGenerator kgen = KeyGenerator.getInstance(Constant.CODEC_NAME);
			kgen.init(128, new SecureRandom(password.getBytes()));
			
			// generate a spec secret key for AES
			SecretKey secretKey = kgen.generateKey();
			byte[] enCodeFormat = secretKey.getEncoded();
			SecretKeySpec key = new SecretKeySpec(enCodeFormat, Constant.CODEC_NAME);
			
			Cipher cipher = Cipher.getInstance(Constant.CODEC_NAME);
			cipher.init(Cipher.ENCRYPT_MODE, key);
			
			// encrypt
			byte[] byteContent = content.getBytes(Constant.CHARACTERS_SET);
			byte[] result = cipher.doFinal(byteContent);
			return result;

		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 
	 * 
	 * @param content	加密过过的内容
	 * @param password	加密时的密码
	 * @return 明文
	 */
	private static byte[] aesDecrypt(byte[] content, String password) {
		try {
			// AES secret key generator
			KeyGenerator kgen = KeyGenerator.getInstance(Constant.CODEC_NAME);
			kgen.init(128, new SecureRandom(password.getBytes()));
			
			// generate a spec secret key for AES
			SecretKey secretKey = kgen.generateKey();
			byte[] enCodeFormat = secretKey.getEncoded();
			SecretKeySpec key = new SecretKeySpec(enCodeFormat, Constant.CODEC_NAME);
			
			Cipher cipher = Cipher.getInstance(Constant.CODEC_NAME);
			cipher.init(Cipher.DECRYPT_MODE, key);
			// decrpt
			byte[] result = cipher.doFinal(content);
			return result; 
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}
}